
#include "PreHeader.h"
#include "cPlayerLogic.h"

#include "cLogicManager.h"
#include "cLogicDataManager.h"
#include "cEnemy.h"
#include "cBullet.h"
#include "cCatmullRomSpline.h"

cPlayerLogic::cPlayerLogic()
{
	m_logicManager = NULL;
	m_boomerangSprite = NULL;
	m_playerSprite = NULL;
	m_streak = NULL;
	m_constantData = NULL;
	m_stone = NULL;

	m_shootAngle = 0.0f;
	m_shootDistance = 0.0f;
	m_shootWidth = 0.0f;
	//m_shooting = false;
	m_stoneLoaded = false;

	m_stop = false;
}

cPlayerLogic::~cPlayerLogic()
{
	
}

void cPlayerLogic::Init(const sPlayerLogicDesc& desc)
{
	m_logicManager = desc.logicManager;
	m_constantData = cLogicDataManager::it()->GetConstantData();

	CCSize screenSize = CCDirector::sharedDirector()->getWinSize();
	m_playerPos = ccp(30.0f, 100.0f);

	// load tongue sprite
	//tFilename spriteFilename = "wonder.png";
	//m_playerSprite = CCSprite::spriteWithFile(spriteFilename.c_str());
	//m_playerSprite->setAnchorPoint(CCPointZero);
	//m_playerSprite->setPosition(ccp(20.0f, 80.0f));
	//m_logicManager->GetSceneNode()->addChild(m_playerSprite, 1);

	//
	CCTexture2D* texture = CCTextureCache::sharedTextureCache()->addImage("wonder.png");
	tFloat size = 32.0f;
	CCSpriteFrame* frame0 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(size, 0, size, size));
	CCSpriteFrame* frame1 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(size, 0, size, size));
	CCSpriteFrame* frame2 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(size*2, 0, size, size));
	CCSpriteFrame* frame3 = CCSpriteFrame::frameWithTexture(texture, CCRectMake(size*3, 0, size, size));

	m_playerSprite = CCSprite::spriteWithSpriteFrame(frame0);
	m_playerSprite->setAnchorPoint(CCPointZero);
	m_playerSprite->setPosition(ccp(20.0f, 80.0f));
	m_logicManager->GetSceneNode()->addChild(m_playerSprite, 1);

	CCMutableArray<CCSpriteFrame*>* animFrames = new CCMutableArray<CCSpriteFrame*>(4);
	animFrames->addObject(frame0);
	animFrames->addObject(frame1);
	animFrames->addObject(frame2);
	animFrames->addObject(frame3);

	CCAnimation *animation = CCAnimation::animationWithFrames(animFrames, 0.1f);
	CCAnimate *animate = CCAnimate::actionWithAnimation(animation, false);
	CCActionInterval* seq = (CCActionInterval*)(CCSequence::actions(animate, animate->reverse(), NULL));
	m_playerSprite->runAction(CCRepeatForever::actionWithAction(seq));
	animFrames->release();    // win32 : memory leak    2010-0415
	//


	// load plater sprite
	m_boomerangSprite = CCSprite::spriteWithFile("boomerang.png");
	m_boomerangSprite->setPosition(m_playerPos);
	m_logicManager->GetSceneNode()->addChild(m_boomerangSprite, 1);

	m_streak = CCMotionStreak::streakWithFade(0.3f, 4.0f, "streak.png", 20.0f, 20.0f, ccc4(100,50,0,100));
	m_logicManager->GetSceneNode()->addChild(m_streak, 1);
}

void cPlayerLogic::Update(tFloat dt)
{
	// update effect
	//for (tInt i = (tInt)eEffect::Long; i < (tInt)eEffect::EOE; i++)
	//{
	//	eEffect::TYPE effect = (eEffect::TYPE)i;
	//	cTimeCounter& timer = m_effectTimer[effect];
	//	if (timer.IsUsing() == false)
	//	{
	//		continue;
	//	}

	//	// update stun
	//	if (effect == eEffect::Stun)
	//	{
	//		tFloat stunTrembleSize = 3.0f;
	//		CCPoint pos = ccpAdd(m_playerPos, ccp(CCRANDOM_MINUS1_1()*stunTrembleSize, CCRANDOM_MINUS1_1()*stunTrembleSize));
	//		m_playerSprite->setPosition(pos);
	//	}

	//	timer.Update(dt);
	//	if (timer.IsDone() == true)
	//	{
	//		RemoveEffect(effect);
	//	}
	//}

	if (m_shootTimer.IsUsing() == true)
	{
		if (m_stopTimer.IsUsing() == true)
		{
			m_stopTimer.Update(dt);
			if (m_stopTimer.IsDone() == true)
			{
				m_stopTimer.Clear();
			}
		}
		else
		{
			m_shootTimer.Update(dt);
			if (m_shootTimer.IsDone() == true)
			{
				m_shootTimer.Clear();
				m_boomerangSprite->setPosition(m_playerPos);
				m_boomerangSprite->setRotation(0.0f);
			}
			else
			{
				tFloat t = m_shootTimer.GetTimer()/m_shootTimer.GetDuration();
				//tFloat t = cTweener::cQuad::Out(m_shootTimer.GetTimer(), 0.0f, 1.0f, m_shootTimer.GetDuration());

				//if (m_stop == false && m_shootTimer.GetTimer() >= m_shootTimer.GetDuration() * 0.5f)
				if (m_stop == false && t >= 0.5f)
				{
					m_stopTimer.Init(0.03f);
					m_stop = true;
				}

				b2Vec2 point = cCatmullRomSpline::Interpolate(t, m_orbitalPointArray);

				m_boomerangSprite->setPosition(ccp(point.x, point.y));
				m_streak->setPosition(ccp(point.x, point.y));
			}

			const b2Vec2& pos = m_orbitalPointArray[2];
			//m_tongueSprite->setPosition(ccp(pos.x, pos.y));

			tFloat rotate = m_boomerangSprite->getRotation();
			rotate += 50.0f;
			m_boomerangSprite->setRotation(rotate);
		}
	}
}

void cPlayerLogic::Reset()
{
	//m_shooting = false;
	m_stoneLoaded = false;
	m_shootTimer.Clear();

	foreach (cTimeCounter& timer, m_effectTimer)
	{
		timer.Clear();
	}

	m_hitIDSet.clear();
}

void cPlayerLogic::Shoot(const CCPoint& lastPos)
{
	if (m_shootTimer.IsUsing() == true || m_effectTimer[eEffect::Stun].IsUsing() == true)
	{
		return;
	}

	//if (m_stoneLoaded == true)
	//{
	//	tFloat stoneSpeed = m_constantData->player.stoneSpeed;
	//	CCPoint direction = ccpSub(lastPos, m_playerPos);
	//	m_shootDirection = ccpMult(ccpNormalize(direction), stoneSpeed);
	//	m_stone->SetPosv(m_shootDirection);

	//	m_stoneLoaded = false;
	//	return;
	//}

	CCSize screenSize = CCDirector::sharedDirector()->getWinSize();
	m_shootDistance = m_constantData->player.shootDistance;
	if (m_effectTimer[eEffect::Long].IsUsing() == true)
	{
		m_shootDistance *= m_constantData->player.longEffectMultiplier;
	}

	//m_shootWidth = m_constantData->player.shootWidth;
	//if (m_effectTimer[eEffect::Broad].IsUsing() == true)
	//{
	//	m_shootWidth *= m_constantData->player.broadEffectMultiplier;
	//}

	CCPoint direction = ccpSub(lastPos, m_playerPos);
	m_shootDirection = ccpNormalize(direction);
	m_shootPoint = m_playerPos;
	m_shootAngle = DIRECTION_TO_ANGLE(m_shootDirection);

	// new
	m_orbitalPointArray.clear();
	m_orbitalPointArray.push_back(b2Vec2(m_playerPos.x, m_playerPos.y));

	const tFloat angleDelta = DegToRad(10.0f);
	const tFloat halfDistance = m_shootDistance*0.5f;

	// angle to direction
	b2Vec2 playerPos(m_playerPos.x, m_playerPos.y);
	b2Vec2 dir(0.0f, 1.0f);
	b2Rot rot(m_shootAngle + angleDelta);
	dir = b2Mul(rot, dir);
	b2Vec2 pos = playerPos + (halfDistance + (halfDistance*0.7f)) * dir;
	m_orbitalPointArray.push_back(pos);

	pos = playerPos + m_shootDistance * b2Vec2(m_shootDirection.x, m_shootDirection.y);
	m_orbitalPointArray.push_back(pos);

	dir.Set(0.0f, 1.0f);
	rot.Set(m_shootAngle - angleDelta);
	dir = b2Mul(rot, dir);
	pos = playerPos + (halfDistance + (halfDistance*0.3f)) * dir;
	m_orbitalPointArray.push_back(pos);
	m_orbitalPointArray.push_back(b2Vec2(m_playerPos.x, m_playerPos.y));
	// new
	
	//if (m_effectTimer[eEffect::Strong].IsUsing() == false)
	//{
	//	sDetectCollisionArg arg;
	//	arg.distance = m_shootDistance;
	//	arg.width = m_shootWidth;
	//	arg.angle = m_shootAngle;
	//	arg.playerPos = m_playerPos;
	//	arg.direction = m_shootDirection;

	//	tEntityDistanceInfoList entityDistanceInfoList;
	//	m_logicManager->DetectCollision(arg, OUT entityDistanceInfoList);

	//	if (entityDistanceInfoList.empty() == false)
	//	{
	//		const sEntityDistanceInfo& info = entityDistanceInfoList.front();

	//		cEnemy* enemy = (cEnemy*)m_logicManager->GetEntity(info.entityID);
	//		if (enemy->GetEnemyType() != eEnemyType::BREAKABLE)
	//		{
	//			m_hitIDSet.insert(info.entityID);
	//		}

	//		m_shootDistance = info.distance;
	//	}
	//}

	tFloat shootOutTime = m_constantData->player.shootOutTime;
	if (m_effectTimer[eEffect::Speed].IsUsing() == true)
	{
		shootOutTime *= m_constantData->player.speedEffectMultiplier;
	}

	//m_tongueSprite->setIsVisible(true);
	m_shootTimer.Init(shootOutTime);
	//m_shooting = true;

	m_stop = false;
	m_stopTimer.Clear();
}

void cPlayerLogic::AddEffect(eEffect::TYPE effectType)
{
	cTimeCounter& timer = m_effectTimer[effectType];

	tFloat effectDuration = 0.0f;
	if (effectType == eEffect::Stun)
	{
		effectDuration = m_constantData->player.stunEffectDuration;
	}
	else
	{
		effectDuration = m_constantData->player.effectDuration;
	}

	timer.Init(effectDuration);
}

void cPlayerLogic::RemoveEffect(eEffect::TYPE effectType)
{
	cTimeCounter& timer = m_effectTimer[effectType];
	timer.Clear();

	if (effectType == eEffect::Stun)
	{
		m_boomerangSprite->setPosition(m_playerPos);
	}
}

void cPlayerLogic::LoadStone(tID entityID)
{
	const nFoodFormat01::sFood* foodData = cLogicDataManager::it()->GetFoodData(entityID);
	if (foodData == NULL)
	{
		return;
	}

	m_stoneLoaded = true;
	
	sCreateBulletArg arg;
	arg.type = eBulletType::NORMAL;
	arg.pos = m_playerPos;
	arg.radius = foodData->collisionRadius;
	arg.spriteFilename = foodData->spriteFilename;

	m_stone = m_logicManager->CreateBullet(arg);
}